﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Yz.Base;
using Yz.Base.ParaModels;
using Yz.Core.Extensions;
using Yz.Core.Tools;

namespace Yz.FileService.Middlewares
{
    public class DownloadMiddleware : BaseUploadMiddleware, IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            #region 跨域上传
            if (context.Request.Method.Equals(HttpMethods.Options, StringComparison.OrdinalIgnoreCase))
            {
                base.AddHttpOptionHeader(context);
            }
            #endregion

            #region 后台post上传
            else if (context.Request.Method.Equals(HttpMethods.Post, StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    #region 验证token
                    await ValidateTokenAsync(context);
                    context.Request.Headers.TryGetValue("appId", out StringValues appId);
                    #endregion

                    StringValues sv = context.Request.Form["application/json"];
                    if (sv == StringValues.Empty)
                    {
                        sv = context.Request.Form["data"];
                    }
                    string fileId = "";
                    if (sv != StringValues.Empty)
                    {
                        var paraFileId = JsonConvert.DeserializeObject<ParaFileId>(sv);
                        if (paraFileId == null || string.IsNullOrEmpty(paraFileId.Id))
                        {
                            await context.Response.WriteAsync(new VmUpFileBase()
                            {
                                msg = "参数不正确！"
                            }.ToJson());
                            return;
                        }
                        fileId = paraFileId.Id;
                    }
                    string filePath = _uploadConfig.PhysicalPath + fileId.ToDes3Decrypt();

                    if (!filePath.Contains(appId))
                    {
                        await context.Response.WriteAsync(new VmUpFileBase()
                        {
                            msg = "您没有权限下载此文件！"
                        }.ToJson());
                        return;
                    }
                    if (!File.Exists(filePath))
                    {
                        await context.Response.WriteAsync(new VmUpFileBase()
                        {
                            msg = "您要下载的文件不存在！"
                        }.ToJson());
                        return;
                    }
                    if (!string.IsNullOrEmpty(_uploadConfig.VirtualPath))
                    {
                        filePath = filePath.Replace(_uploadConfig.VirtualPath, _uploadConfig.PhysicalPath);
                    }
                    int dataBufferSize = _uploadConfig.DownloadSize;   //每次分批加载的50m 
                    string fileName = filePath.Substring(filePath.LastIndexOf("/") + 1);
                    string fileExt = fileName.Substring(fileName.LastIndexOf("."));
                    var provider = new FileExtensionContentTypeProvider();
                    var contentType = provider.Mappings[fileExt];
                    fileName = HttpUtility.UrlEncode(fileName);
                    context.Response.Clear();
                    context.Response.Headers.Add("fileName", fileName);
                    context.Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileName);
                    context.Response.ContentType = contentType;
                    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        long contentLength = stream.Length;
                        byte[] buffer;
                        long hasRead = 0;//变量hasRead用于记录已经发送了多少字节的数据到客户端浏览器
                        //context.Response.Clear();
                        //如果hasRead小于contentLength，说明下载文件还没读取完毕，继续循环读取下载文件的内容，并发送到客户端浏览器
                        while (hasRead < contentLength)
                        {
                            buffer = new byte[dataBufferSize];
                            int currentRead = await stream.ReadAsync(buffer, 0, dataBufferSize);//从数据流中读取bufferSize大小的内容到服务器内存中
                            await context.Response.Body.WriteAsync(buffer, 0, currentRead);//发送读取的内容数据到客户端浏览器
                            await context.Response.Body.FlushAsync(); //注意每次Write后，要及时调用Flush方法，及时释放服务器内存空间
                            hasRead += currentRead;//更新已经发送到客户端浏览器的字节数
                        } 
                        return; 
                    }
                }
                catch (Exception ex)
                {
                    YzNLog.Error(ex);
                    await context.Response.WriteAsync(new VmUpFileBase()
                    {
                        msg = "文件下载失败"
                    }.ToJson());
                }
            }
            #endregion

            #region 非法上传
            else
            {
                await base.AddHttpNotAllowedAsync(context);
            }
            #endregion 
        }
    }
}
